from datetime import datetime
from dateutil.relativedelta import relativedelta,calendar
from dateutil.parser import parse
from utils import Enum

import dateutil.rrule as rrule
from dateutil.parser import parse





      
class Daily(datetime):
    PERIOD=365   
    def __init__(self, *args,**kargs):
        super(datetime,self).__init__(*args)
        self.replace(hour=0,minute=0, second=0, day=1,microsecond=0)
        
    def __str__(self):
        return "%s %s" % ('Daily',self.strftime('%Y-%m-%d'))
    
class TTSE(Daily):
    PERIODS=154
class Business(Daily):
    PERIODS = 250
class Weekly(Daily):
    PERIODS = 52
class Monthly(Daily):
    PERIODS = 12
class Quarterly(Daily):
    PERIODS = 4
class SemiAnnaul(Daily):
    PERIODS = 2
class Yearly(Daily):
    PERIODS = 1
class Hourly(Daily):
    PERIOD = 8760
class TTSE_Hourly(Daily):
     PERIOD = 924
class Secondly(Daily):
     PERIOD = 31536000
class Minuetly(Daily):
     PERIOD = 525600
     
def qtr_to_month(qtr):
    """
    Return the month associated with a quarter.
    This is the first month in the quarter
    """
    qdict={1:1,2:4,3:7,4:10}
    return qdict[qtr]

def month_to_qtr(month):
    """
    Returns the quarter number associated with the month
    """
    if month <=3:
        return 1
    elif month > 3 and month <=6:
        return 2
    elif month > 6 and month <=9:
        return 3
    elif month >9 and month <=12:
        return 4
    else: 
        raise ValueError ,"Invalid month: (%s)" % (month)
    
def date_parse(datestr):
    """Parse Date Formats"""
    try:
        return parse(datestr)
    except ValueError:
        #we have two extra productions  yyyy-Q[1-4] and yyyy-S[1-2]
        
        year,oth = datestr.split('-')
        if oth[0] not in ('Q','S'): raise ValueError,'Invalid date'
        if oth[0] == 'Q':
            return datetime(int(year),qtr_to_month(int(oth[1])),1)   
        elif oth[0] == 'S':
            if oth[1] == 1:
               return datetime(int(year),int(1),1)
            else:
               return datetime(int(year),7,1)
           
        else:
            raise TypeError, "We do not support this date format" % (datestr)
       
def normalize_date(datein,date_type,weekday=4):
    """ removes extras date attributes from a datetime instance 
        and ensures that datein is a datetime instance in the 
        specified Calendar
    """
    
    if date_type == Monthly:
        return datein.replace(hour=0,minute=0, second=0, day=1,microsecond=0)
    elif date_type == Daily:
        return datein.replace(hour=0,minute=0, second=0,microsecond=0)
    elif date_type == Business:
        dd =datein.replace(hour=0,minute=0, second=0,microsecond=0)
        if dd.weekday() in (5,6):
            dd1 = dd+relativedelta(weekday=0)
            return dd1
        else:
            return dd 
    elif date_type == Quarterly:
         if datein.month in (1,2,3):
            return datein.replace(month=1, hour=0,minute=0, second=0, day=1,microsecond=0)
         elif datein.month in (4,5,6):
            return datein.replace(month=4,hour=0,minute=0, second=0, day=1,microscond=0)
         elif datein.month in (7,8,9):
            return datetin.replace(month=7,hour=0,minute=0, second=0, day=1,microsecond=0)
         else:
            return datetin.replace(month=10,hour=0,minute=0, second=0, day=1,microscond=0)
    elif date_type == Weekly:
         dd =datein.replace(hour=0,minute=0, second=0,microsecond=0)
         if dd.weekday() != weekday:
             #the  date is set to isoweekday after the datein
             dd1=dd+relativedelta(weekday=weekday)
             return dd1
         else:
             return dd       
    elif date_type == TTSE:
         dd =datein.replace(hour=0,minute=0, second=0,microsecond=0)
         if dd.weekday() in (1,2,4):
             return dd
         elif dd.weekday() in (0,3):
             return dd + relativedelta(days=1)
         else:
             return dd + relativedelta(weekday=1)
    elif date_type == Hourly:
        return datein.replace(minute=0, second=0,microsecond=0)
             
    elif date_type == TTSE_Hourly:
        dd = datein.replace(minute=0, second=0,microsecond=0)
        if dd.hour in (9,10,11,12,13,14):
            return dd
        elif dd.hour < 9:
             return dd.replace(hour=9)
        elif dd.hour > 14:
             return dd+relativedelta(days=1,hour=9)
    else:
        raise TypeError,"We do not support this date_type" % str(date_type)
        
def calendar_helper(start_date,
                    end_date=None,
                    count=None,
                    date_type=Daily,
                    weekday=None,
                    interval_size=1):

    """Returns an rrule to match the frequency specified"""
    
    
    if isinstance(start_date,str):
        dstart=normalize_date(date_parse(start_date),freq_str=freq_str,weekday=weekday)
    else:
        dstart = normalize_date(start_date,freq_str=freq_str,weekday=weekday)

    if isinstance(end_date_date,str):
        dend=normalize_date(date_parse(start_date),freq_str=freq_str,weekday=weekday)
    else:
        dend = normalize_date(start_date,freq_str=freq_str,weekday=weekday)
    if count:
        dend=None
    

    if date_type== Daily:
             #set 
        return rrule.rrule(rrule.DAILY,dtstart=dstart,
                        interval=interval,count=count,until=dend)
    
    elif date_type == Business:
         return rrule.rrule(rrule.WEEKLY,dtstart =dstart,
                            interval=interval_size,
                            count=count,
                            byweekday=(rrule.MO,rrule.TU,rrule.WE,rrule.TH,rrule.FR))
    elif date_type == TTSE:
        return rrule.rrule(rrule.WEEKLY,dtstart =dstart,
                            interval=interval_size,
                            count=count,
                            byweekday=(rrule.TU,rrule.WE,rrule.FR),until=dend)
    elif date_type == Weekly:
         return rule.rrule(rrule.WEEKLY,dtstart =dstart,
                            interval=interval_size,
                            count=count,until=dend)
    elif date_type == Monthly:
        return rrule.rrule(rrule.MONTHLY,dtstart=dstart,
                        interval=interval,count=count,until=dend)
    elif date_type == SemiAnnaul:
        return rrule.rrule(rrule.MONTHLY,dtstart=dstart,
                        interval=6*interval,count=count,until=dend)
    elif date_type == Yearly:
        return rrule.rrule(rrule.YEARLY,dtstart=dstart,
                        interval=interval,count=count,until=dend)
    elif date_type == Hourly:
        return rrule.rrule(rrule.HOURLY,dtstart=dstart,
                           intrval=interval_size,count=count,until=dend) 
    elif date_type == TTSE_Hourly:    
        return rrule.rrule(rrule.HOURLY,dtstart=dstart,byhour=(9,10,11,12,13,14),
                           intrval=interval_size,count=count,until=dend)
    elif date_type == Minuetly:
        return rrule.rrule(rrule.MINUTELY,dtstart=dstart,
                           intrval=interval_size,count=count,until=dend)
    
    elif date_type == Secondly:
        return rrule.rrule(rrule.SECONDLY,dtstart=dstart,
                           intrval=interval_size,count=count,until=dend)    
        
    
     
if __name__ == '__main__':  
    pass
   #x=TSDelta(unit='months',size=1)
   #print x._value


